package com.motu.monstercity.server.gate;

import com.motu.monstercity.module.common.network.DataDecoded;
import com.motu.monstercity.module.common.network.ResponseUtils;
import com.motu.monstercity.module.common.redis.RedisKey;
import com.motu.monstercity.module.common.servermanager.ServerInfo;
import com.motu.monstercity.module.common.servermanager.ServerManager;
import com.motu.monstercity.module.common.utility.Constant;
import com.motu.monstercity.module.common.utility.EventBusConstant;
import com.motu.monstercity.module.common.utility.ServerParam;
import com.motu.monstercity.protocol.CmdEnum;
import com.motu.monstercity.protocol.CmdEnum.EnumCmdID;
import com.motu.monstercity.protocol.CsGameSystem.CSGameInitRequest;
import com.motu.monstercity.protocol.CsGameSystem.CSGameInitResponse;
import com.motu.monstercity.protocol.CsGameSystem.CSGameSystemLogicErrorResponseType;
import com.motu.monstercity.protocol.CsGameSystem.CSGameSystemPingpongResponse;
import com.motu.vertx.module.utility.base.ServerConfig;
import com.motu.vertx.module.utility.commondata.CommonDataManager;
import com.motu.vertx.module.utility.monitor.MonitorManager;
import com.motu.vertx.module.utility.mysql.MysqlClient;
import com.motu.vertx.module.utility.mysql.MysqlTool;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.threadpool.DBLogManager;
import com.motu.vertx.module.utility.toolset.ErrorWord;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.ServerWebSocket;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;


public class WebsocketVerticle extends AbstractVerticle {
    public static final Logger logger = LoggerFactory.getLogger("monstercity-game");
    public static ConcurrentHashMap<ServerWebSocket, Buffer> userBuffer = new ConcurrentHashMap<>();//用户分帧数据

    @Override
    public void start(Promise<Void> future) throws Exception {
        Router router = Router.router(vertx);
        router.route().handler(BodyHandler.create(false));
        router.route().handler(CorsHandler.create("*"));
        router.get("/health").handler(this::ping);
        HttpServerOptions options = new HttpServerOptions();
        options.setIdleTimeout(60);// 创建连接n秒没有响应则会断开连接
        vertx.createHttpServer(options)
                .webSocketHandler(ws -> {// 客户端创建连接响应事件第2步
                    if (ServerParam.BAN_CONNECT_GATE == 1) {//禁止连接网关
                        logger.info("websocket reject ban connect gate !!!!!!");
                        ws.reject();
                        return;
                    }
                    if (ServerParam.CONNECT_GATE_MAX > 0) {//连接单个网关进程最大数量
                        int connectNum = SocketManager.getSocketList().size();
                        if (connectNum >= ServerParam.CONNECT_GATE_MAX) {
                            logger.info("websocket reject server socket num = " + connectNum + " max connect num = " + ServerParam.CONNECT_GATE_MAX + " !!!!!!");
                            ws.reject();
                            return;
                        }
                    }
                    switch (ws.path()) {
                        case "/game/admin":
                            onAdminConnection(ws);
                            break;
                        case "/game":
                            onPlayerConnection(ws);
                            break;
                        default:
                            logger.warn(String.format("Connection to web socket %1$s not supported", ws.path()));
                            ws.reject();
                    }
                })
                .connectionHandler(con -> {// 客户端创建连接响应事件第1步
                    //			logger.info("accept connection "+con.remoteAddress());
                })
                .requestHandler(router)
                .listen(config().getInteger("websocket-port"), ar -> {
                    if (ar.succeeded()) {
                        logger.info(String.format("Gate server started on 0.0.0.0:%1$d ", ar.result().actualPort()));
                        future.complete();
                    } else {
                        future.fail(ar.cause());
                    }
                });

    }

    /***
     * 读取userextinfo信息
     * @param userId 用户id
     * @return 返回key按数据库字段名
     */
    private Future<JsonObject> getUserExtInfo(long userId) {
        Promise<JsonObject> fut = Promise.promise();
        String tableName = "user_ext_info";
        String userExtInfoKey = RedisKey.getUserExtInfoKey(userId);
        RedisTools.getHashJsonObject(userExtInfoKey, res -> {
            JsonObject redisResultObj = res.result(); // !!! 新规范下redis字段名会可能和数据库不一样 !!!
            if (redisResultObj != null) {
                if (!redisResultObj.containsKey("id")) {//从数据库中再读取一下
                    String sql = "SELECT account_id,platform FROM " + tableName + " WHERE id = ?";
                    JsonArray params = new JsonArray();
                    params.add(userId);
                    MysqlTool.queryJsonArrayFromDb(MysqlClient.getGamePool(), sql, params, handler -> {
                        if (handler.succeeded()) {
                            if (handler.result().size() > 0) {
                                JsonObject dbobj = handler.result().getJsonObject(0);
                                fut.complete(dbobj);
                            } else {
                                fut.fail("has not user!");
                                logger.error("### has not user getUserExtInfo:" + userId);
                            }
                        } else {
                            fut.fail(handler.cause().getMessage());
                            logger.error(handler.cause().getMessage());
                        }
                    });
                } else {
                    // !!! 新规范下redis字段名会可能和数据库不一样 !!!
                    String account = redisResultObj.getString("accountId");
                    int platform = Tool.stringToInt(redisResultObj.getString("platform"));
                    JsonObject redisObj = new JsonObject().put("account_id", account).put("platform", platform);
                    fut.complete(redisObj);
                }
            } else {
                fut.fail("redis query failed");
                logger.error("### redis query failed getUserExtInfo:" + userId);
            }
        });
        return fut.future();
    }

    private void handleEvent(long userId, String ebName, ServerWebSocket socket, DataDecoded reqPacket) {

        if (userId == 0) {
            logger.error("handleEvent userId = 0!! ");
            try {
                socket.end();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
//        if (ServerManager.isBanned(null, 0, userId, null, null)) {//被封号了
//            MainVerticle.instance.socketManager.kickUser(userId, socket, language, ErrorWord.BANNED_ACCOUNT);
//            return;
//        }


//		ServerWebSocket socketInfo = MainVerticle.instance.socketManager.getSocket(userId);
        ServerInfo server = ServerManager.getServerInfo(SocketInfo.getServerId(socket));
        if (server != null && server.getStatus() == ServerInfo.SERVER_STATUS_MAINTAIN) {//服务器在维护中
            Future<JsonObject> fut = getUserExtInfo(userId);
            fut.onComplete(handler -> {
                if (handler.succeeded()) {
                    JsonObject obj = fut.result();
                    String account = obj.getString("account_id");
                    int platform = obj.getInteger("platform");

                    String ip = Tool.getClientIp(socket);
                    if (!MonitorManager.isWhiteList(account, ip, platform)) {
                        ResponseUtils.sendError(socket, reqPacket, ErrorWord.SERVER_MAINTAIN, server.getDes(reqPacket.getLanguage()), CSGameSystemLogicErrorResponseType.confirm, null, false);
                        return;
                    }
                    handleEvent2(userId, ebName, socket, reqPacket);
                } else {
                    ResponseUtils.sendError(socket, reqPacket, ErrorWord.REDIS_QUERY_FAILED);
                    logger.error(handler.cause().getMessage());
                }
            });
        } else {
            handleEvent2(userId, ebName, socket, reqPacket);
        }

    }

    private void handleEvent2(long userId, String ebName, ServerWebSocket socketInfo, DataDecoded reqPacket) {
        handleEvent2(userId, ebName, socketInfo, reqPacket, true);
    }

    private void handleEvent2(long userId, String ebName, ServerWebSocket socketInfo, DataDecoded reqPacket, boolean clientRequest) {
        int messageId = reqPacket.getMessageId();
        int cmdCode = reqPacket.getCmdCode();
        byte[] pbdata = reqPacket.getReqData();

        if (messageId > 0 && cmdCode != CmdEnum.EnumCmdID.CMD_GAME_SYSTEM_INIT_VALUE && cmdCode != CmdEnum.EnumCmdID.CMD_GAME_SYSTEM_RELOAD_VALUE) {
            MessageCache messageCache = SocketManager.getMessageCache(userId);
            if (messageCache != null) {
//                logger.info("handleEvent2 userid:{},messageId:{},cmdCode:{},cacheId:{}", userId, messageId, cmdCode, messageCache.getMessageId());

                if (messageCache.getMessageId() == messageId && messageCache.getCmdCode() == cmdCode) {
                    //重发最后一条缓存的消息
                    logger.info("resend cache message userid:{},messageId:{},cmdCode:{},resCode:{},resDataLen:{}", userId, messageId, cmdCode, messageCache.getresCode(), messageCache.getResData().length);
//                    WebsocketVerticle.sendResponse(socketInfo, messageCache.getresCode(), messageCache.getResData(), messageCache.getMessageId());
                    return;
                }
            }
        }
        // 队列执行
//        if (SocketManager.isMessageQueueWay()) {
//            SocketManager.addMessageQueue(userId, new MessageInfo(vertx, userId, cmdCode, pbdata, language, messageId, socketInfo));
//            return;
//        }

        EventBus eventBus = vertx.eventBus();
        //		long startTime = System.currentTimeMillis();
//		System.out.println(" ### handleEvent2 send thread name = " + Thread.currentThread().getName());
        JsonObject obj = new JsonObject().put("lan", reqPacket.getLanguage()).put("uid", userId).put("code", cmdCode).put("data", pbdata).put("mid", messageId);


        if (clientRequest) {
            ConcurrentLinkedQueue<DataDecoded> userQueue = SocketManager.userRequestQueueMap.get(userId);
            if (userQueue == null) {
                userQueue = new ConcurrentLinkedQueue<>();
                SocketManager.userRequestQueueMap.put(userId, userQueue);
            }
            boolean sendNow = false;// 是否现在发送
            if (userQueue.isEmpty()) {
                sendNow = true;
            }
            obj.put("ebname", ebName);
            int queueSize = userQueue.size();
            if (queueSize > ServerParam.USER_REQUEST_MAX) {
                logger.info("request too fast userid = " + userId + " queueSize = " + queueSize);
                ResponseUtils.sendError(socketInfo, reqPacket, ErrorWord.FREQUENTLY_OPEARTE);
                return;
            }
            userQueue.add(reqPacket);
//			if (cmdCode == 74201 || cmdCode == 70602){// 抽卡
//				logger.info(" ### userid = " + userId + " cmd = " + cmdCode + " send now = " + sendNow);
//			}
            if (!sendNow) {
                return;
            }
        }

        // 如果测试服游戏进程没有启动，则访问备份进程
        Future<Boolean> future = SocketManager.checkGameStart(eventBus, ebName);
        future.onComplete(res -> {
            String eventBusName = ebName;
            if (ServerConfig.isDebugServer() && !res.result()) {
                eventBusName += EventBusConstant.BACKUPS;
            }
            long startTime = System.currentTimeMillis();
//		if (cmdCode == 74201 || cmdCode == 70602){// 抽卡
//			logger.info(" ### userid = " + userId + " cmd = " + cmdCode + " send request");
//		}
            eventBus.request(eventBusName, obj, ar -> {
                if (ar.succeeded()) {
                    JsonObject recData = (JsonObject) ar.result().body();
                    SocketManager.requestGameCallback(recData, socketInfo, userId, reqPacket, startTime);
                } else {
                    EnumCmdID eid = CmdEnum.EnumCmdID.forNumber(cmdCode);
                    String cmdName = eid != null ? eid.name() : String.valueOf(cmdCode);
                    String errorMsg = "eventBus.send failed userid:" + userId + " cmdName:" + cmdName + " cause:" + ar.cause().getMessage();
                    logger.error(errorMsg);
					DBLogManager.addServerCrashLog(userId, errorMsg);
                    ResponseUtils.sendError(socketInfo, reqPacket, ErrorWord.NET_ERROR_TIMEOUT);
                }

                // 移除当前命令并执行下一个命令
                ConcurrentLinkedQueue<DataDecoded> userQueue1 = SocketManager.userRequestQueueMap.get(userId);
                if (userQueue1 != null) {
                    userQueue1.poll();// 移除当前命令
                    DataDecoded nextPacket = userQueue1.peek();// 取下一条命名
                    if (nextPacket != null) {
//                        String nextEbname = nextPacket.getString("ebname");
//                        int nextCmdCode = nextPacket.getInteger("code");
//                        byte[] nextPbdata = nextPacket.getBinary("data");
//                        int messageId3 = nextPacket.getInteger("messageId");
                        handleEvent2(userId, ebName, socketInfo, nextPacket, false);
//                        handleEvent2(userId, nextEbname, nextCmdCode, nextPbdata, socketInfo, reqPacket.getLanguage(), false, messageId3);
                    }
                }
            });
        });
    }

    /***
     * 处理消息
     * @param socket
     */
    private void handleMessage(ServerWebSocket socket, DataDecoded reqPacket) {
//        int cmdCode, byte[] pbdata, ServerWebSocket socket, int language, int messageId
        //		String cmdName = CmdEnum.EnumCmdID.forNumber(cmdCode).name();
        if (reqPacket.getCmdCode() == 0) {
            ResponseUtils.sendError(socket, reqPacket, ErrorWord.PROTOCOL_UNDEFINE);
            return;
        }
        try {
            //			EnumCmdID e = CmdEnum.EnumCmdID.forNumber(cmdCode);
            //			if(e == null){//未定义的协议如果返回出错，则每次新增协议都要重新编译gate，开发阶段先注释
            //				logger.info("handleMessage undefine cmdCode:"+cmdCode);
            //				//				sendResponseError(socket,cmdCode, Constant.NET_ERROR_UNDEFINE_CMD);
            //				//				return;
            //			}else{
            //				String cmdName = e.name();
            ////				logger.info("handleMessage cmdName:"+cmdName);
            //			}
            //协议临时关闭
            if (MonitorManager.checkProtocolBanned(reqPacket.getCmdCode())) {
                ResponseUtils.sendError(socket, reqPacket, ErrorWord.PROTOCOL_BANNED, false);
                return;
            }
            switch (reqPacket.getCmdCode()) {
//                case CmdEnum.EnumCmdID.CMD_GAME_SYSTEM_TEST_VALUE:
//                    handleGameSystemTest(cmdCode, CmdEnum.EnumCmdID.CMD_GAME_SYSTEM_TEST.name(), pbdata, socket, language);
//                    break;
                case CmdEnum.EnumCmdID.CMD_GAME_INIT_VALUE:
                    handleGameInit(socket, reqPacket);
                    break;
//                case CmdEnum.EnumCmdID.CMD_GAME_INIT_TEST_VALUE:
//                    handleGameInitTest(cmdCode, CmdEnum.EnumCmdID.CMD_GAME_INIT_TEST.name(), pbdata, socket, language);
//                    break;
                case CmdEnum.EnumCmdID.CMD_GAME_SYSTEM_PINGPONG_VALUE:
                    handlePingpong(socket, reqPacket);
                    break;
//				case EnumCmdID.CMD_GAME_CHAT_WORLD_JOIN_VALUE:
//					SocketInfo.setChatWorld(socket, 1);// 标记玩家处在跨服聊天界面
//					CsGameChat.CSGameChatWorldJoinResponse.Builder res_build = CsGameChat.CSGameChatWorldJoinResponse.newBuilder();
//					sendResponse(socket, cmdCode, res_build.build().toByteArray());
//					break;
//				case EnumCmdID.CMD_GAME_CHAT_WORLD_LEFT_VALUE:
//					SocketInfo.setChatWorld(socket, 0);// 标记玩家离开跨服聊天界面
//					CsGameChat.CSGameChatWorldLeftResponse.Builder res_build2 = CsGameChat.CSGameChatWorldLeftResponse.newBuilder();
//					sendResponse(socket, cmdCode, res_build2.build().toByteArray());
//					break;
                default:
                    long userId = SocketInfo.getUserId(socket);
                    if (userId == 0) {
                        logger.error("### handleMessage fail userid = 0 !!!");
                        return;
                    }
                    handleEvent(userId, EventBusConstant.getAddress(EventBusConstant.GAME_LOGIC),  socket, reqPacket);
                    break;
            }
            ;
        } catch (Exception e) {
            logger.error("handleMessage exception:{}", Tool.getException(e));
            ResponseUtils.sendError(socket, reqPacket, ErrorWord.NET_ERROR_GATESERVER_EXCEPTIION);
        }
    }

    /***
     * 处理心跳包响应
     * @param socket
     */
    private void handlePingpong(ServerWebSocket socket, DataDecoded reqPacket) throws Exception {
        CSGameSystemPingpongResponse.Builder response = CSGameSystemPingpongResponse.newBuilder();
        ResponseUtils.send(socket, reqPacket.getCmdCode(), response.build().toByteArray(), reqPacket);
    }

//    private void handleGameSystemTest(int cmdCode, String cmdName, byte[] pbdata, ServerWebSocket socket, int language) {
//        CSGameSystemTestResponse.Builder res_build = CSGameSystemTestResponse.newBuilder();
//        try {
////			 ByteArrayInputStream in = new ByteArrayInputStream(pbdata);
////				ObjectInputStream input = new ObjectInputStream(in);
//
//            CSGameSystemTestRequest clientReq = CSGameSystemTestRequest.parseFrom(pbdata);
////			String strVal = clientReq.getStrVal();
////			int intVal = clientReq.getIntVal();
////			long longVal = clientReq.getLongVal();
////			float floatVal = clientReq.getFloatVal();
////			double doubleVal = clientReq.getDoubleVal();
////			boolean bolVal = clientReq.getBolVal();
////			PBTest pbtest = clientReq.getPbtest();
////			logger.info("### doTest strVal:"+strVal);
////			logger.info("### doTest intVal:"+intVal);
////			logger.info("### doTest longVal:"+longVal);
////			logger.info("### doTest floatVal:"+floatVal);
////			logger.info("### doTest doubleVal:"+doubleVal);
////			logger.info("### doTest bolVal:"+bolVal);
////			logger.info("### doTest pbtest.name:"+pbtest.getName()+" age:"+pbtest.getAge());
////			List<PBTest> testList = clientReq.getListTestList();
////			int i=0;
////			for(PBTest pt:testList) {
////				i++;
////				logger.info("### doTest "+i+" pbtest.name:"+pt.getName()+" age:"+pt.getAge());
////				res_build.addListTest(pt);
////			}
////			res_build.setPbtest(pbtest);
////			res_build.setStrVal(strVal);
////			res_build.setIntVal(intVal);
////			res_build.setLongVal(longVal);
////			res_build.setFloatVal(floatVal);
////			res_build.setDoubleVal(doubleVal);
////			res_build.setBolVal(bolVal);
//            sendResponse(socket, cmdCode, res_build.build().toByteArray(),0);
//
//        } catch (IOException e) {
//            sendResponseAndClose(socket, cmdCode, cmdName, ErrorWord.REDIS_QUERY_EMPTY, language, null);
//        }
//    }

    /***
     * 处理初始化接口
     * @param socket
     */
    private void handleGameInit(ServerWebSocket socket, DataDecoded reqPacket) throws Exception {
        CSGameInitRequest clientReq = CSGameInitRequest.parseFrom(reqPacket.getReqData());

        // 判断是否有在线数量限制
        Promise<Void> promiseOnline = Promise.promise();
        if (ServerParam.USER_ONLINE_MAX > 0) {
            RedisTools.get(RedisKey.getUserOnlineKey(), resOnline -> {
                long onlineNum = Tool.isEmpty(resOnline.result()) ? 0 : Long.parseLong(resOnline.result());
                if (onlineNum >= ServerParam.USER_ONLINE_MAX) {
                    promiseOnline.fail("");
                } else {
                    promiseOnline.complete();
                }
            });
        } else {
            promiseOnline.complete();
        }

        promiseOnline.future().onComplete(resOnlineLimit -> {
            if (resOnlineLimit.failed()) {
                logger.warn("handleGameInit online limit userId:{} accountId:{}", clientReq.getUserId(), clientReq.getAccount());
                ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.ALREADY_MAX);
                return;
            }
            logger.info("handleGameInit userId:{} accountId:{}", clientReq.getUserId(), clientReq.getAccount());
            int accountType = clientReq.getAccountType();
            String redisKey = RedisKey.getAccountToken(accountType, clientReq.getAccount());
            RedisTools.getHashJsonObject(redisKey, res -> {
                if (res.result() != null) {
                    if (!res.result().isEmpty() && res.result().getString("token").equalsIgnoreCase(clientReq.getToken())) {//验证token
                        int tokenTime = Integer.parseInt(res.result().getString("tokentime"));
                        if (TimeUtils.getCurTime() - tokenTime > Constant.TOKEN_EXPIRED_TIME) {//token过期失效了
                            ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.TOKEN_EXPIRED);
                        } else {//开始初始化用户信息
                            long userId = clientReq.getUserId();
                            if (userId <= 0) {//用户id不能为0
                                ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.BAD_PARAM);
                                return;
                            }
                            Future<JsonObject> fut = getUserExtInfo(userId);
                            fut.onComplete(handler -> {
                                if (handler.succeeded()) {
                                    JsonObject obj = fut.result();
                                    String account = obj.getString("account_id");
                                    int platform = clientReq.getPlatform();//obj.getInteger("platform"); 这边用客户端上行的platform值
                                    // 判断该渠道是否能登陆
                                    if (ServerParam.BAN_LOGIN_PLATFORM != null && Tool.isInList(ServerParam.BAN_LOGIN_PLATFORM, platform)) {
                                        ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.WRONG_STATUS, false);
                                        return;
                                    }
                                    if (!account.equalsIgnoreCase(clientReq.getAccount())) {//客户端提交的账号id跟数据库中不一致，判断是否为GM托管
                                        if (!CommonDataManager.isHostedUser(accountType, clientReq.getAccount(), userId)) {//不在托管列表，那就是错误的账号了
                                            ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.INVALID_OPERATION);
                                            return;
                                        } else {
                                            // 如果是托管登录，则给socket对象设置一个标识，托管之后不允许顶号
                                            SocketInfo.setHosted(socket, 1);
                                            logger.info("handleGameInit hostedAccount:{} userAccount:{} userId:{}", clientReq.getAccount(), account, userId);
                                        }
                                    }
                                    String ip = Tool.getClientIp(socket);
                                    ServerInfo server = ServerManager.getServerInfo(clientReq.getServerId());
                                    if (server.getStatus() == ServerInfo.SERVER_STATUS_MAINTAIN) {//服务器在维护中
                                        if (!MonitorManager.isWhiteList(account, ip, platform)) {
                                            ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.SERVER_MAINTAIN, server.getDes(reqPacket.getLanguage()), CSGameSystemLogicErrorResponseType.confirm, null, false);
                                            return;
                                        }
                                    }

                                    // 判断之前是否有托管登录
                                    if (SocketManager.getSocketList().containsKey(userId)) {
                                        ServerWebSocket oldSocket = SocketManager.getSocketList().get(userId);
                                        if (SocketInfo.isHosted(oldSocket)) {
                                            logger.warn("handleGameInit fail hosted userId:{}", userId);
                                            ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.LOGIN_REPLACE);
                                            return;
                                        }
                                    }

                                    CSGameInitResponse.Builder response = CSGameInitResponse.newBuilder();
                                    ResponseUtils.send(socket, reqPacket.getCmdCode(), response.build().toByteArray(), reqPacket);
                                    JsonObject userGateObj = new JsonObject();
                                    String deviceInfo = clientReq.getDeviceInfo();
                                    if (deviceInfo != null && !deviceInfo.isEmpty()) {
//                                    logger.info("user " + userId + " init deviceInfo:" + deviceInfo);
                                        userGateObj = new JsonObject(deviceInfo);
                                    }
                                    // 判断福利号验证设备信息
//                                    if (!ServerManager.checkWelfareDevice(userId, userGateObj.getString("deviceid"))) {
//                                        sendResponseAndClose(socket, cmdCode, cmdName, ErrorWord.WRONG_STATUS, language, null);
//                                        return;
//                                    }
                                    userGateObj.put("gate_name", ServerConfig.getGateName());
                                    userGateObj.put("ip", ip);
                                    userGateObj.put("platform", platform);
                                    userGateObj.put("channel", clientReq.getChannel());
									userGateObj.put("accountId", account);
									userGateObj.put("serverId", server.getServerId());
									SocketManager.addSocket(clientReq.getAccount(), clientReq.getUserId(), server.getServerId(), socket, reqPacket.getLanguage(), userGateObj, platform);


                                    //									handleEvent(userId,Constant.getEventBusName(MainVerticle.isLocalServer(),Constant.EVENT_BUS_GAME_LOGIC), cmdCode, pbdata, socket,language);
                                } else {
                                    ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.REDIS_QUERY_FAILED);
                                    logger.error(handler.cause().getMessage());
                                }
                            });

                        }
                    } else {//可能还需要在redis取出来是空的时候从数据库再取一次

//						int code = ErrorWord.TOKEN_WRONG.value;
                        ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.TOKEN_WRONG);

                    }
                } else {
                    ResponseUtils.sendErrorAndClose(socket, reqPacket, ErrorWord.REDIS_QUERY_EMPTY);
                }
            });
        });
    }

//    private void handleGameInitTest(int cmdCode, String cmdName, byte[] pbdata, ServerWebSocket socket, int language) {
//        try {
//            CSGameInitRequest clientReq = CSGameInitRequest.parseFrom(pbdata);
//            CSGameInitResponse.Builder res_build = CSGameInitResponse.newBuilder();
//            sendResponse(socket, cmdCode, res_build.build().toByteArray(), 0);
//            JsonObject userGateObj = new JsonObject();
//            userGateObj.put("gate_name", ServerConfig.getGateName());
//            SocketManager.addSocket(clientReq.getAccount(), clientReq.getUserId(), clientReq.getServerId(), socket, language, userGateObj, 0);
//        } catch (InvalidProtocolBufferException e) {
//            logger.error(e.getMessage());
//        }
//    }

//    private void sendResponseAndClose(ServerWebSocket socket, int cmdCode, String cmdName, ErrorWord er, int language, String errMsg) {
//        CSGameSystemLogicErrorResponse.Builder res_build = CSGameSystemLogicErrorResponse.newBuilder();
//        res_build.setCmdCode(cmdCode);
//        res_build.setRet(er.value);
//        if (errMsg == null) {
//            errMsg = ErrorWordManager.get(cmdName, er, language);
//        } else {
//            errMsg = WordManager.getWordByLanguage(errMsg, language);
//        }
//        res_build.setErrMsg(errMsg);
//        sendResponseAndClose(socket, EnumCmdID.CMD_GAME_SYSTEM_LOGIC_ERROR_VALUE, res_build.build().toByteArray());
//
//    }
//
//    private void sendResponseAndClose(ServerWebSocket socket, int cmdCode, String cmdName, ErrorWord er, int language, String errMsg, boolean confirm) {
//        CSGameSystemLogicErrorResponse.Builder res_build = CSGameSystemLogicErrorResponse.newBuilder();
//        res_build.setCmdCode(cmdCode);
//        res_build.setRet(er.value);
//        if (errMsg == null) {
//            errMsg = ErrorWordManager.get(cmdName, er, language);
//        } else {
//            errMsg = WordManager.getWordByLanguage(errMsg, language);
//        }
//        res_build.setErrMsg(errMsg);
//        if (confirm) {
//            res_build.setParam("confirm");// 二次确认框
//        }
//        sendResponseAndClose(socket, EnumCmdID.CMD_GAME_SYSTEM_LOGIC_ERROR_VALUE, res_build.build().toByteArray());
//
//    }
//
//    private void sendResponseError(ServerWebSocket socket, int cmdCode, String cmdName, ErrorWord er, int language, byte[] request, int messageId) {
//        CSGameSystemLogicErrorResponse.Builder res_build = CSGameSystemLogicErrorResponse.newBuilder();
//        res_build.setCmdCode(cmdCode);
//        res_build.setRet(er.value);
//        res_build.setErrMsg(ErrorWordManager.get(cmdName, er, language));
//        sendResponse(socket, EnumCmdID.CMD_GAME_SYSTEM_LOGIC_ERROR_VALUE, res_build.build().toByteArray(), messageId);
//        JsonObject obj = Constant.getErrorCodeObj(0, cmdName, "", er, cmdCode, request);
////        DBLogManager.addLog(obj);
//        DbManager.pushLogDBQueue(obj);// 改成kafka写日志
//    }
//
//    private void sendResponseError(ServerWebSocket socket, int cmdCode, String cmdName, ErrorWord er, String errMsg, boolean confirm, byte[] request, int messageId) {
////        logger.info("sendResponseError cmdName:" + cmdName + " errMsg:" + errMsg);
//        CSGameSystemLogicErrorResponse.Builder res_build = CSGameSystemLogicErrorResponse.newBuilder();
//        res_build.setCmdCode(cmdCode);
//        res_build.setRet(er.value);
//        res_build.setErrMsg(errMsg);
//        if (confirm) {
//            res_build.setParam("confirm");// 二次确认框
//        }
//        sendResponse(socket, EnumCmdID.CMD_GAME_SYSTEM_LOGIC_ERROR_VALUE, res_build.build().toByteArray(), messageId);
//        if (er.value != ErrorWord.SERVER_MAINTAIN.value) {
//            JsonObject obj = Constant.getErrorCodeObj(0, cmdName, "", er, cmdCode, request);
////            DBLogManager.addLog(obj);
//            DbManager.pushLogDBQueue(obj);// 改成kafka写日志
//        }
//    }

    private void manageWebSocket(String announceAddress, ServerWebSocket socket) {
        socket
                .exceptionHandler(Throwable::printStackTrace)
                .frameHandler(frame -> {// 收到客户端数据响应事件
                    //			logger.info("manageWebSocket frame len:"+frame.binaryData().length()+" frame.isBinary() "+frame.isBinary());
                    try {
                        Buffer data;
                        //分帧处理
                        if (!frame.isFinal()) {
                            //取出之前的数据追加再存进去
                            Buffer temp = userBuffer.get(socket);
                            if (temp == null) {
                                userBuffer.put(socket, frame.binaryData());
                            } else {
                                temp.appendBuffer(frame.binaryData());
                                userBuffer.put(socket, temp);
                            }
                            return;
                        } else {
                            if (userBuffer.containsKey(socket)) {
                                data = userBuffer.get(socket);
                                data.appendBuffer(frame.binaryData());
                                userBuffer.remove(socket);
                            } else {
                                data = frame.binaryData();
                            }
                        }

                        if (ServerConfig.isWechatGame()) {
                            JsonObject obj = new JsonObject(data);
                            Buffer buffer2 = Buffer.buffer();
                            for (int i = 0; i < obj.size(); i++) {
                                buffer2.appendByte(obj.getInteger("" + i).byteValue());
                            }
                            data = buffer2;
                        }
                        DataDecoded reqPacket = new DataDecoded(data);
                        handleMessage(socket, reqPacket);
                    } catch (Exception e) {
//                        logger.error("manageWebSocket error ip:{}", SocketManager.getClientIp(socket));
                    }

                }).closeHandler(h -> {// 关闭连接响应事件
                    // 清空用户请求队列
                    long userId = SocketInfo.getUserId(socket);
                    if (userId == 0) {
                        return;
                    }
                    ConcurrentLinkedQueue<DataDecoded> userRequestQueue = SocketManager.userRequestQueueMap.get(userId);
                    if (userRequestQueue != null) {
                        userRequestQueue.clear();
                    }
                    SocketManager.removeWebSocket(userId, socket);
                });
    }

    private void onAdminConnection(ServerWebSocket socket) {
        manageWebSocket("admin", socket);
    }

    private void onPlayerConnection(ServerWebSocket socket) {
        manageWebSocket("player", socket);
    }

    private void ping(RoutingContext context) {
        context.response().setStatusCode(200).end(ServerConfig.getGateName() + " service is running!!");
    }

//    public static void sendResponse(ServerWebSocket socket, int cmdCode, byte data[], int messageId) {
////        logger.info("sendResponse cmdCode:{},data.len:{},messageId:{}",cmdCode,data.length,messageId);
//        try {
//            if (!socket.isClosed()) {
//                data = doLanguage(socket, cmdCode, data);
//                if (data != null) {
//                    socket.writeFinalBinaryFrame(DataEncoded.encode(cmdCode, (byte) 0, data, messageId));
////                    logger.info("sendResponse success cmdCode:{},data.len:{},messageId:{}",cmdCode,data.length,messageId);
//                }
//            }
//        } catch (Exception e) {
//            logger.error(Tool.getException(e));
//        }
//    }
//
//    public static void sendResponseAndClose(ServerWebSocket socket, int cmdCode, byte data[]) {
//        try {
//            if (!socket.isClosed()) {
//                socket.end(DataEncoded.encode(cmdCode, (byte) 0, data, 0));
//            }
//        } catch (Exception e) {
//            logger.error(Tool.getException(e));
//        }
//    }

    /**
     * 多语言处理
     */
    public static byte[] doLanguage(ServerWebSocket socket, int cmdCode, byte data[]) {
//        if (cmdCode == EnumCmdID.CMD_GAME_SYSTEM_ROLLNOTICE_VALUE) {// 推送滚动公告
//            try {
//                int language = SocketInfo.getLanguage(socket);
//                if (language == 0) {
//                    return data;
//                }
//                CSGameSystemRollnoticeResponse response = CSGameSystemRollnoticeResponse.parseFrom(data);
//                String content = WordManager.getWordByLanguage(response.getContent(), language);
//                if (Tool.isEmpty(content)) {
//                    return null;
//                }
//                if (response.getContent().equals(content)) {
//                    return data;
//                } else {
//                    CSGameSystemRollnoticeResponse.Builder builder = response.toBuilder();
//                    builder.setContent(content);
//                    return builder.build().toByteArray();
//                }
//            } catch (Exception e) {
//                logger.error(Tool.getException(e));
//            }
//        }
        return data;
    }

    //	private void sendResponseError(ServerWebSocket socket,int cmdCode,byte error){
    //		byte data[] = new byte[0];
    //		try {
    ////			socket.writeFinalBinaryFrame(DataEncoded.encode(cmdCode,error, data));
    //			socket.writeFinalBinaryFrame(DataEncoded.encode(0,error, data));
    //		} catch (Exception e) {
    //			logger.error(Tool.getException(e));
    //			e.printStackTrace();
    //		}
    //	}
}
